// /www/client.bumpz.js
// provide global main to spaceport
// initial load and enterFrame game loop
//
// Harald Rudell
// David DC Collier

var SCALE = 40;
var PLAYERSIZE = 100
var CLICK_FORCE = 0.5;  // power of clicking

var world, stage, library;
var boxes = [];

var   b2Vec2 = Box2D.Common.Math.b2Vec2
,	b2BodyDef = Box2D.Dynamics.b2BodyDef
,	b2Body = Box2D.Dynamics.b2Body
,	b2FixtureDef = Box2D.Dynamics.b2FixtureDef
,	b2Fixture = Box2D.Dynamics.b2Fixture
,	b2World = Box2D.Dynamics.b2World
,	b2MassData = Box2D.Collision.Shapes.b2MassData
,	b2PolygonShape = Box2D.Collision.Shapes.b2PolygonShape
,	b2CircleShape = Box2D.Collision.Shapes.b2CircleShape
,	b2DebugDraw = Box2D.Dynamics.b2DebugDraw
;

// global main is invoked by spaceport at onLoad
// purpose: one-time initialization, bind enterframe method to spaceport
// stg: Stage object
// TODO: make stage a non-global variable
function main(stg) {
  
    // all game properties bound to this object
    var gameengine = {}
    gameengine.stage = stg // sp.Stage Adobe class
    gameengine.libraryURL = "/assets/bumpz.swf"
    gameengine.loadLibrary = loadLibrary
    gameengine.launcher = launch

    // TODO remove references to global stage
    stage = stg;

//    addBackground(stage);

    // enterFrame in closure that has gameEngine
    // this is DOMWindow
    gameengine.enterFrame = function(event) {
  
    try {
      
      gameengine.networkgameclient.getNewPlayers().forEach(function(player) {
        console.log('new player:' + player.id + ' at ' + (new Date()) + player.r)
        gameengine.addBox(player.x, player.y, "player", player.r, player.id)
      })

      gameengine.networkgameclient.getDeadPlayers().forEach(function(playerid) {
        console.log('dead player:' + playerid + ' at ' + (new Date()))
        var boxes = gameengine.boxes
        for (var index in boxes) {
          if (boxes[index].id = playerid) {
            boxes.splice(index, 1)
          }
        }
        // TODO delete as in removeBox here
      })

      world.Step(
        1 / 30.0,	// time step
        2,	 		// velocity iterations
        2			// position iterations
      );
      
      gameengine.boxes.forEach(function(box) {
        var rig = box.body.m_body.m_xf;
        var pos = rig.position;
        box.view.x = (pos.x * SCALE);
        box.view.y = (pos.y * SCALE);
        var vec = rig.R.col1;

        // dont rotate the players cos it looks ugly
        if (box.itemType == "player") {
            box.view.rotation = 0;
        } else {
            box.view.rotation = -Math.atan2(vec.x, vec.y) * 180.0 / Math.PI;
        }

//        if (vec.x < 0) {
//          box.view.scaleX =  1;
//        } else {
//          box.view.scaleX = -1;
//        }


      })
        
      world.ClearForces();
      
    } catch(e) { // exception in enterFrame
      console.log(e.stack)
      debugger;
    }
  } // enterFrame
  
  // addBox need to be accessible from gameengine, and have gameengine in closure
  gameengine.addBox = function(x, y, itemType, itemNumber, id) { //console.log('new box at:' + x + ',' + y)
    var box = new Box(x, y, PLAYERSIZE / SCALE, PLAYERSIZE / SCALE, itemType, itemNumber, id);
    box.body.type = b2Body.b2_dynamicBody;

    var result = {body: box.addToWorld(world), view: box.view, itemType: itemType };

    boxes.push(result);

    gameengine.removeBox = function (event) {
      // Don't go to stage
      event.stopImmediatePropagation();

      // remove from list
      boxes.splice(boxes.indexOf(result), 1);

      stage.removeChild(result.view);
      world.DestroyBody(result.body.m_body);
    }

    function hitPlayer(event) {
      log(event)
      event.stopImmediatePropagation();
      // result.view.gotoAndPlay("clicked");
      // result.GetUserData().clip.gotoAndPlay("clicked");
      bump(result, event);
    }

    box.view.addEventListener(sp.TouchEvent.TOUCH_BEGIN, hitPlayer);
    box.view.addEventListener(sp.MouseEvent.MOUSE_DOWN, hitPlayer);

    stage.addChild(box.view);
  }
  
  gameengine.loadLibrary()

} // main


// get the library, then do one-time initialization
function loadLibrary() {
  // closure variable for callback
  var gameengine = this
  var libraryLoader = new sp.Loader();
  var libraryURLRequest = new sp.URLRequest(this.libraryURL);
  libraryLoader.load(libraryURLRequest);
  libraryLoader.contentLoaderInfo.addEventListener(sp.Event.COMPLETE, function libraryLoaded(event) {
    // TODO: remove this global variable
    library = libraryLoader.contentLoaderInfo.applicationDomain;
    
    gameengine.library = library
    try {
      gameengine.launcher()
      console.log('launch successful at ' + (new Date()))
    } catch(e) { // exception in launcher
      console.log(e.stack)
      debugger
    }
  });
}

// launch: one-time initialization
function launch() {

    var vgrav = 1.0;
    
    // get world from physics.js
    this.world = new b2World(new b2Vec2(0.0, vgrav),  true);

    // TODO: get rid of this global variable
    world = this.world

    addWalls(world, stage);
    addBackground(stage)
    setupContacts(world);
    addScore(stage);

    this.boxes = boxes

  // this DomWindow
	function onStageClick(event) {
		if(boxes.length > 10) return;
		// this.addBox(event.stageX / SCALE, event.stageY / SCALE, "goodThing");
	};

    stage.addEventListener(sp.TouchEvent.TOUCH_BEGIN, onStageClick);
    stage.addEventListener(sp.MouseEvent.MOUSE_DOWN, onStageClick);

	var orientation = new sp.Accelerometer();
	orientation.addEventListener(sp.AccelerometerEvent.UPDATE, function(event) {
		world.SetGravity(new b2Vec2(-event.y * SCALE / 2, -event.x * SCALE / 2));

		// Wake all boxes
		for(var i=0; i<boxes.length; ++i)
			boxes[i].body.m_body.SetAwake(true);
	});
  
  // initialization is ready, now start the game
  var myx = Math.random() * stage.stageWidth  / SCALE
  var myy = Math.random() * stage.stageHeight / SCALE
  var digit
  var playerId = '' // 4-digit random string
  for (var i = 0; i < 4; i++) {
    digit = randomInt(10) // random 0 - 9
    playerId += digit
  }
  var imageNumber = digit % 4 + 1; // 1 - 4 based on least significant digit

  // ready to create items: launch network in /server/scripts/game-client.js
  var gameengine = this
  this.networkgameclient = new NetworkGameClient(playerId, myx, myy, imageNumber, function(gc) {
    gameengine.addBox(myx, myy, "player", imageNumber, 'p' + playerId);
    gameengine.addBox(Math.random() * stage.stageWidth / SCALE, Math.random() * stage.stageHeight / SCALE,
      "goodThing");

    gc.start();
    // start drawing the view
    gameengine.stage.addEventListener(sp.Event.ENTER_FRAME, gameengine.enterFrame)
  });
  
} // launch

// getLibrary is invoked the first time by main
// TODO: should be a field of some object like world or such
function getLibrary() {
  if (typeof library == 'undefined' || !library) {
    throw 'race condition: getLibrary called before main completed'
  }
  return library
}

// stuff below here should probably be moved out of bumpz.js

Box.prototype = {
	addToWorld: function(world) {
		this.world = world;

		return world.CreateBody(this.body).CreateFixture(this.fixture);
	}
};


function addWalls(world, stage) {
    var ground = new Box(0, stage.stageHeight / SCALE + 0.5, stage.stageWidth, 1, "wall");
    ground.body.type = b2Body.b2_staticBody;
    ground.addToWorld(world);

    var leftWall = new Box(-0.5, stage.stageHeight / 2 / SCALE, 1, stage.stageHeight / SCALE, "wall");
    leftWall.body.type = b2Body.b2_staticBody;
    leftWall.addToWorld(world);

    var rightWall = new Box(stage.stageWidth / SCALE + 0.5, stage.stageHeight / 2 / SCALE, 1, stage.stageHeight / SCALE, "wall");
    rightWall.body.type = b2Body.b2_staticBody;
    rightWall.addToWorld(world);

    var ceiling = new Box(stage.stageWidth / SCALE / 2, -0.5, stage.stageWidth / SCALE, 1, "wall");
    ceiling.body.type = b2Body.b2_staticBody;
    ceiling.addToWorld(world);
}



function bump(box, evt) {
    // log("evt: " + evt.localX + "," + evt.localY )
    // log(box.view.width)

    // dx = ((box.view.width/2) - evt.localX)  * CLICK_FORCE;
    // dy = ((box.view.height/2) - evt.localY) * CLICK_FORCE;
    dx = - evt.localX * CLICK_FORCE;
    dy = - evt.localY * CLICK_FORCE;

    log("dx,dy= " + dx + "," + dy);

    body = box.body.GetBody();
    force=new b2Vec2(dx, dy);
    body.ApplyImpulse(force,body.GetWorldCenter());
    return box;
}

var tmp;


function setupContacts(world) {
    log("setupContacts")
    var listener = new Box2D.Dynamics.b2ContactListener;
    listener.BeginContact = function(contact) {
        objA = contact.GetFixtureA().GetBody();
        objB = contact.GetFixtureB().GetBody();

        dataA = objA.GetUserData();
        dataB = objB.GetUserData();

        if (dataA.itemType.indexOf("pet") != -1 &&
            dataB.itemType == "goodThing") {

            scorePoint()

            log("HIT");

            /////WTF this doesnt work on one axis
            // objB.view.width = 50;
            // objB.view.height = 50;
            // objB.view.gotoAndPlay("vanish");
            tmp = objB;
            dataA.clip.gotoAndPlay("happy");
            dataB.clip.gotoAndPlay("vanish");

            force=new b2Vec2(0, 50);
            objB.ApplyImpulse(force, objB.GetWorldCenter() )
            
            // objB.position.y = 0;
            // objB.GetTransform().position.y = 100;

            ///// KABOOM. this freezes firefox
            // vec = new b2Vec2(0, 50);
            // var angle = 0;
            // objB.SetTransform(vec, angle);
        } else {
            // log("unknown collision:" + dataA.itemType + " & " + dataB.itemType);
        }

    }
    listener.EndContact = function(contact) {
        //console.log(contact.GetFixtureA().GetBody().GetUserData());
    }
    listener.PostSolve = function(contact, impulse) {

    }
    listener.PreSolve = function(contact, oldManifold) {

    }
    world.SetContactListener(listener);

}


//public class GameContactFilter extends b2ContactFilter
//{
//        public override function ShouldCollide(shape1:b2Shape, shape2:b2Shape) : Boolean
//        {
//                // Custom collisions for game objects
//                var obj1:GameObj = shape1.GetBody().GetUserData() as GameObj;
//                var obj2:GameObj = shape2.GetBody().GetUserData() as GameObj;
//
//                if (obj1 && obj2)
//                {
//                        if (obj1.CanCollide(obj2) && obj2.CanCollide(obj1))
//                        {
//                                return true;
//                        }
//                }
//                return false;
//        }
//}
//
